package model.auxillary;

import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;

/**
 * A {@code ParameterCollection} holds parameters of the same type. 
 * @author Oliver Eckstein
 *
 */
public class ParameterCollection {
	
	/**
	 * Description for this collection. Can be used in the frames inside
	 * the input parameter window. 
	 */
	protected String desc;
	
	/**
	 * The name of the process that belongs to this {@code ParameterCollection}.
	 */
	private String procName;
	
	/**
	 * Sub string of every parameter's id. 
	 */
	private String idString;
	
	/**
	 * Parameters of this collection.
	 */
	protected List<Parameter> parameters;	
	
	/**
	 * Identifying ID for a parameter 
	 */
	private long paramID;
	
	/**
	 * Number of parameters in this collection
	 */
	private int parametersCount;
	
	/**
	 * The ID of the part process that holds this {@code ParameterCollection}.
	 */
	private String partProcessID;
	
	/**
	 * To create a new {@code ParameterCollection} for a {@code PartProcess}.
	 * @param desc the description of this collection.
	 * @param procName the name of the connected part process.
	 * @param idString an identifying ID.
	 * @param partProcessID the part process' ID.
	 */
	public ParameterCollection(
			String desc,
			String procName,
			String idString,
			String partProcessID) {
		this.desc = desc;
		this.procName = procName;
		this.idString = idString;
		this.partProcessID = partProcessID;
		parameters = new ArrayList<Parameter>();
		paramID = 0;
		parametersCount = 0;		
	}
	
	/**
	 * To create a new {@code ParameterCollection}. This constructor is mainly
	 * used to create a new {@code Tool}.
	 * @param desc the description of this collection.
	 * @param idString an identifying ID.
	 * @param partProcessID the part process' ID.
	 */
	public ParameterCollection(
			String desc,			
			String idString,
			String partProcessID) {
		this.desc = desc;		
		this.idString = idString;
		this.partProcessID = partProcessID;
		parameters = new ArrayList<Parameter>();
		paramID = 0;
		parametersCount = 0;
	}
	
	/**
	 * To get the name of this {@code ParameterCollection}.
	 * @return the name.
	 */
	public String getName() {
		return desc + procName;
	}
	
	/**
	 * To change the name of this collection's part process name.
	 * @param procName the new name of the part process.
	 */
	public void setName(String procName) {		
		this.procName = procName;
	}
	
	/**
	 * To get all parameters of this {@code ParameterCollection}.
	 * @return
	 */
	public List<Parameter> getParameters() {
		return parameters;
	}
	
	/**
	 * To add a new parameter to this {@code ParameterCollection}.
	 * @param param the parameter to be added.
	 */
	public void addParameter(Parameter param) {
		parameters.add(param);
		parametersCount++;
	}
	
	/**
	 * To add several parameters to this {@code ParameterCollection}.
	 * @param parameterList the parameters to be added.
	 */
	public void addParameters(List<Parameter> parameterList) {
		for (Parameter param : parameterList) {
			param.setOrder(getParamCount());
			param.setKey(getNewID());
		}
		parameters.addAll(parameterList);
	}
	
	/**
	 * To remove a certain parameter from this {@code ParameterCollection}.
	 * @param param the parameter to be removed.
	 */
	public void removeParameter(Parameter param) {
		if (parameters.contains(param)) {
			parameters.remove(param);
			parametersCount--;
		} else {
			throw new NoSuchElementException(
					this + " does not hold " + param);
		}		
	}
	
	/**
	 * To get a certain parameter by it's identifying key.
	 * @param parameterKey the parameter's key.
	 * @return the parameter. Returns {@code null} when parameter does not
	 * exist.
	 */
	public Parameter getParameter(String parameterKey) {
		for (Parameter param : parameters) {
			if (param.getKey().equals(parameterKey)) {
				return param;
			}
		}
		return null;
	}
	
	/**
	 * To get a parameter by it's abbreviation
	 * @param abbreviation the parameter's abbreviation	 
	 * @return the parameter. Returns {@code null} when parameter does not
	 * exist.
	 */
	public Parameter getParameterByAbbrev(String abbreviation) {
		for (Parameter param : parameters) {
			if (param.getAbbreviation().equals(abbreviation)) {
				return param;
			}
		}		
		return null;
	}
	
	/**
	 * To get a unique ID when creating a new parameter.
	 * @return
	 */
	public String getNewID() {
		return idString + "_" + paramID++;
	}
	
	/**
	 * To get the ID of this {@code ParameterCollection}.
	 * @return the ID.
	 */
	public String getID() {
		return idString;
	}
	
	/**
	 * To get the number of parameters inside this {@code ParameterCollection}.
	 * @return the number of parameters.
	 */
	public int getParamCount() {
		return parametersCount;
	}	
	
	@Override
	public String toString() {
		return desc + procName;
	}
	
	/**
	 * To get the number of parameters that must be set by the user.
	 * @return the number of user dependent parameters.
	 */
	public int getUserSetParametersCount() {
		int count = 0;
		for (Parameter param : parameters) {
			if (param.isSetByUser()) {
				count++;
			}
		}
		return count;
	}
	
	/**
	 * Whether all parameters that have to be set by the user are set or not.
	 * @return <b>true</b> when all parameters are set.
	 */
	public boolean allSet() {
		for (Parameter param : parameters) {
			if (param.isSetByUser() && !param.isSet()) {
				return false;
			}
		}
		return true;
	}
	
	/**
	 * To get the ID of the part process that holds this
	 * {@code ParameterCollection}.
	 * @return the ID.
	 */
	public String getPartProcessID() {
		return partProcessID;
	}
}
